#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <string.h>
#include <sys/epoll.h>
#include <nodelist.h>
#include <threadpool.h>
#include <errmessage.h>

PT_nodeList p_tNodeListHead=NULL;

/*
*	函数功能：		初始化节点双向链表
*	函数参数	：	无
*	函数返回值：节点头指针
*				成功：0
*				失败：<0
*/
int nodeList_init(void)
{
	PT_nodeList me=NULL;

	me = malloc(sizeof(*me));
	if(me ==NULL)
	{
		syslog(LOG_ERR,"workList init error");
		return -1;
	}

	me->client_fd 		= -1;
	me->detect_fd 		= -1;
	me->epoll_fd		= -1;
	me->pos				= -1;
	me->recvDataLenth 	= 0;
	me->lastUpdateTime 	= 0;
	me->recvDataBuff 	= NULL;
	me->prev 			= NULL;
	me->next 			= NULL;
	memset(me->client_id,0,IDSIZE);

	p_tNodeListHead = me;
	return 0;
}

/*
*	函数功能：		在链表中查看指定文件描述符是否存在
*	函数参数	：	要查找的文件描述符
*	函数返回值：节点指针
*				成功：节点地址
*				失败：NULL
*/
PT_nodeList findNode_fd_unLock(int fd)
{
	PT_nodeList me = p_tNodeListHead;

	while(me != NULL)
	{
		if(me->client_fd == fd)
			return me;
		me = me->next;
	}

	return NULL;
}

/*
*	函数功能：		在链表中查看指定的设备ID是否存在
*	函数参数	：	要查找的设备ID
*	函数返回值：节点指针
*				成功：节点地址
*				失败：NULL
*/
PT_nodeList findNode_id_unLock(char *id)
{
	PT_nodeList me = p_tNodeListHead;

	while(me != NULL)
	{
		if(strncmp(id,me->client_id,IDSIZE)==0)
			return me;
		me = me->next;
	}

	return NULL;
}

/*
*	函数功能：		显示nodeList列表
*	函数参数	：	无
*	函数返回值：无
*/
static void showNodeList(void)
{
	PT_nodeList me = p_tNodeListHead;
	int i=0;

	while(me !=NULL)
	{
		fprintf(stdout,"%03d-->client:%d detect:%d epoll:%d ID:%s\n",i++,me->client_fd,me->detect_fd,me->epoll_fd,me->client_id);
		me = me->next;
	}
	for(i=0;i<THREADNUM;i++)
	{
		fprintf(stdout,"%d %03d\n",i,g_pthreadPool->sumEpollDetectFdNum[i]);
	}
}

/*
*	函数功能：		在链表中添加一个节点（类头插法）
*	函数参数	：	1、哪个epoll
*				2、客户端文件描述符
*	函数返回值：是否成功
*				成功：0
*				失败：<0
*/
int nodeList_addNode_unLock(int pos, int epollfd, int clientfd)
{
	PT_nodeList me		= NULL;
	PT_nodeList temp 	= p_tNodeListHead;
	
	if(epollfd<0 || clientfd<0)
	{
		syslog(LOG_ERR,"nodeList addNode params error");
		err_message(clientfd, PARAMAS_ERR);
		return -1;
	}	
	
	me = findNode_fd_unLock(clientfd);
	if(me !=NULL)
	{
		syslog(LOG_ERR,"nodeList clientfd already in");
		err_message(clientfd, CLIET_ERR);
		close(clientfd);
		return -2;
	}

	me = malloc(sizeof(*me));
	if(me ==NULL)
	{
		syslog(LOG_ERR,"nodeList malloc error");
		close(clientfd);
		return -3;
	}

	me->client_fd 		= clientfd;
	me->detect_fd 		= -1;
	me->epoll_fd		= epollfd;
	me->pos				= pos;
	me->recvDataLenth 	= 0;
	me->lastUpdateTime 	= time(NULL);
	me->recvDataBuff 	= NULL;
	me->prev 			= NULL;
	me->next 			= NULL;
	memset(me->client_id,0,IDSIZE);

	if(temp->next==NULL)
	{
		me->prev = temp;
		temp->next = me;
	}
	else
	{
		me->prev = temp;
		me->next = temp->next;
		temp->next->prev = me;
		temp->next = me;
	}

#if DEBUG
	showNodeList();
#endif
	
	return 0;
}

/*
*	函数功能：		更改nodeList链表中的一个节点
*	函数参数	：	1、PT_nodeList指针
*				2、客户端ID
*				3、监视设备ID
*	函数返回值：是否成功
*				成功：0
*				失败：<0
*/
int nodeList_editNode_unLock(PT_nodeList me, char *client_id, char *detect_id)
{
	PT_nodeList temp = NULL;

	if(client_id ==NULL || me==NULL)
	{
		syslog(LOG_ERR,"nodeList editNode param error");
		err_message(me->client_fd, PARAMAS_ERR);
		return -1;
	}

	temp = findNode_id_unLock(client_id);
	if(temp !=NULL)
	{
		syslog(LOG_ERR,"nodeList editNode client_id already in");
		err_message(me->client_fd, CLIENTID_ERR);
		return -2;
	}

	if(detect_id ==NULL)  //正常客服端加入
	{
		me->recvDataBuff = malloc(DATABUFFSZIE);
		if(me->recvDataBuff ==NULL)
		{
			syslog(LOG_ERR,"nodeList editNode malloc error");
			return -3;
		}
		me->lastUpdateTime 	= time(NULL);
		memcpy(me->client_id, client_id, IDSIZE);
	}
	else //监控客服端加入
	{
		temp = findNode_id_unLock(detect_id);
		if(temp ==NULL)
		{
			syslog(LOG_ERR,"nodeList editNode can't find detect_id");
			err_message(me->client_fd, DETECTID_ERR);
			return -4;
		}

		me->recvDataBuff = malloc(DATABUFFSZIE);
		if(me->recvDataBuff ==NULL)
		{
			syslog(LOG_ERR,"nodeList editNode malloc error");
			return -5;
		}
		me->detect_fd = temp->client_fd;
		me->lastUpdateTime 	= time(NULL);
		memcpy(me->client_id, client_id, IDSIZE);

		temp->detect_fd = me->client_fd;
	}

#if DEBUG
		showNodeList();
#endif

	return 0;
}

/*
*	函数功能：		删除nodeList链表中的一个节点
*	函数参数	：	1、指定那个epoll
*				2、客服端文件描述符
*	函数返回值：是否成功
*				成功：0
*				失败：<0
*/
int nodeList_delNode_unLock(int clientfd)
{
	PT_nodeList me = NULL;
	PT_nodeList temp =NULL;
	int detectfd =-1;
	int ret =0;

	if(clientfd <0)
	{
		syslog(LOG_ERR,"nodeList delNode param error");
		err_message(clientfd, PARAMAS_ERR);
		return -1;
	}

	me = findNode_fd_unLock(clientfd);
	if(me ==NULL)
	{
		syslog(LOG_ERR,"nodeList can't find clientfd");
		err_message(clientfd, CLIENTID_ERR);
		return -2;
	}

	ret = epoll_ctl(me->epoll_fd, EPOLL_CTL_DEL, clientfd, NULL);
	if(ret <0)
	{
		syslog(LOG_ERR,"epoll del clientfd error");
		err_message(clientfd, CLIET_ERR);
		return -3;
	}
	g_pthreadPool->sumEpollDetectFdNum[me->pos] --;

	close(clientfd);

	if(me->detect_fd !=-1)
		detectfd = me->detect_fd;

	if(me->recvDataBuff!=NULL)
		free(me->recvDataBuff);

	if(detectfd ==-1)
	{
		if(me->next==NULL)
		{
			me->prev->next =NULL;
		}
		else
		{
			temp = me;
			temp->prev->next = me->next;
			temp->next->prev = me->prev;
		}
		free(me);
	}
	else
	{
		if(me->next==NULL)
		{
			me->prev->next =NULL;
		}
		else
		{
			temp = me;
			temp->prev->next = me->next;
			temp->next->prev = me->prev;
		}
		free(me);

		me = findNode_fd_unLock(detectfd);
		if(me ==NULL)
		{
			syslog(LOG_ERR,"nodeList can't find detectfd");
			err_message(clientfd, DETECT_ERR);
			return -4;
		}
		me->detect_fd =-1;
	}

#if DEBUG
		showNodeList();
#endif

	return 0;
}

/*
*	函数功能：		销毁nodeList链表
*/
void nodeList_destroy(void)
{
	PT_nodeList me = p_tNodeListHead;
	PT_nodeList temp =NULL;

	while(me!=NULL)
	{
		if(me->recvDataBuff!=NULL)
			free(me->recvDataBuff);
		if(me->client_fd >=0)
			close(temp->client_fd);
		temp = me;
		me = me->next;
		free(temp);
	}

	syslog(LOG_DEBUG,"nodeList del sucess");
}

/*
*	函数功能：		nodeList链表指定文件描述符的上报时间
*	函数参数	：	PT_nodeList指针
*	函数返回值：是否成功
*				成功：0
*				失败：<0
*/
int nodeList_updateTime(PT_nodeList me)
{	

	if((me !=NULL) && (me->recvDataBuff !=NULL))
	{
		me->lastUpdateTime = time(NULL);
		return 0;
	}

	return -1;
}

